package fr.labri.macchiato.framework.business.sparql;


/**
 * <p>
 * SparqlQueryBuilder implements a set of methods to build a Sparql query
 * according to the Sparql specification that can be found at 
 * {@link "http://www.w3.org/TR/sparql11-query/"} <br>
 * When building a new query, the first method to call is
 * <code>newQuery()</code>
 * </p>
 * 
 * @author Matthieu FOUCAULT
 */
public class SparqlQueryBuilder implements QueryBuilder {

	private static final String PREFIX = "PREFIX ";
	private static final String PREFIX_SEPARATOR = ":";
	private static final String PREFIX_END = " ";

	private static final String SELECT = "SELECT DISTINCT";
	private static final String SELECT_CLAUSE_SEPARATOR = " ";

	private static final String WHERE = " WHERE { ";
	private static final String WHERE_CLAUSE_SEPARATOR = ". ";
	private static final String WHERE_CLAUSE_END = "}";
	
	private static final String UNION = " { ";
	private static final String UNION_SEPARATOR = "} UNION {";
	private static final String UNION_END = "}";

	private static final String VARIABLE_PREFIX = "?";
	private static final String TYPE_PROPERTY = "a";
	
	private static final String TRIPLE_PATTERN_SEPARATOR = " ";

	private static final String LIMIT = " LIMIT ";
	private static final String FILTER = "FILTER ";
	private static final String REGEX = "regex(";
	private static final String REGEX_SEPARATOR = ", ";
	private static final String REGEX_END = ")";
	
	private static final String ORDER_BY = " ORDER BY ";
	private static final String DESC = "DESC(";
	private static final String DESC_END = ")";

	private String prefixes;
	private String selectClause;
	private String whereClause;
	private String orderByClause;
	private String limitClause;

	@Override
	public void newQuery() {
		prefixes = "";
		selectClause = SELECT;
		whereClause = WHERE;
		limitClause = "";
		orderByClause = "";
	}

	@Override
	public void addPrefix(String name, String value) {
		String prefix = PREFIX + name + PREFIX_SEPARATOR + value + PREFIX_END;
		prefixes += prefix;
	}

	@Override
	public void setSelectFields(String... fields) {
		for (String field : fields) {
			if (field != "*")
				selectClause += SELECT_CLAUSE_SEPARATOR + VARIABLE_PREFIX
						+ field;
			else
				selectClause += SELECT_CLAUSE_SEPARATOR + field;

		}

	}
	
	@Override
	public void setOrderBy(String field, boolean isAscOrder) {
		orderByClause = ORDER_BY;
		if (isAscOrder)
			orderByClause +=VARIABLE_PREFIX + field;
		else
			orderByClause += DESC + VARIABLE_PREFIX + field + DESC_END;
		
	}

	@Override
	public void setLimit(int limit) {
		limitClause = LIMIT + limit;

	}

	@Override
	public void addTypeCriterion(String field, String type) {
		String clause = VARIABLE_PREFIX + field + TRIPLE_PATTERN_SEPARATOR
				+ TYPE_PROPERTY + TRIPLE_PATTERN_SEPARATOR + type
				+ WHERE_CLAUSE_SEPARATOR;
		whereClause += clause;

	}

	@Override
	public void addPropertyCriterion(String varName, String propertyName,
			String toVarName) {
		String clause = VARIABLE_PREFIX + varName + TRIPLE_PATTERN_SEPARATOR
				+ propertyName + TRIPLE_PATTERN_SEPARATOR + VARIABLE_PREFIX
				+ toVarName + WHERE_CLAUSE_SEPARATOR;
		whereClause += clause;
	}

	@Override
	public void addRegexFilter(String filteredVar, String regex, String flags) {
		String filter = FILTER + REGEX + VARIABLE_PREFIX + filteredVar + REGEX_SEPARATOR + '"' + regex + '"' 
				+ REGEX_SEPARATOR + '"' + flags + '"' + REGEX_END + WHERE_CLAUSE_SEPARATOR;
		whereClause += filter;
	}
	
	@Override
	public void beginUnionClauses() {
		whereClause += UNION;
	}
	
	@Override
	public void addUnionClause() {
		whereClause += UNION_SEPARATOR;
	}
	
	@Override
	public void endUnionClauses() {
		whereClause += UNION_END;
	}

	@Override
	public String getQuery() {
		String query = prefixes + selectClause + whereClause + WHERE_CLAUSE_END
				+ orderByClause + limitClause;
		return query;
	}

}
